#include <array>
#include <benchmark/benchmark.h>
#include <cstddef>
#include <random>
#include <vector>

constexpr std::size_t kOperandsPerGroup = 6;

// 为了强调依赖链，禁止内联。
[[gnu::noinline]] float SequentialAdds(const float* values) noexcept {
    float x = values[0] + values[1];
    x = x + values[2];
    x = x + values[3];
    x = x + values[4];
    x = x + values[5];
    return x;
}

[[gnu::noinline]] float PairwiseAdds(const float* values) noexcept {
    const float x = values[0] + values[1];
    const float p = values[2] + values[3];
    const float q = values[4] + values[5];
    const float r = x + p;
    return r + q;
}

std::vector<float> MakeOperands(std::size_t groups) {
    std::vector<float> data(groups * kOperandsPerGroup);
    std::mt19937 rng{123};
    std::uniform_real_distribution<float> dist(-1.0f, 1.0f);

    for (float& v : data) {
        v = dist(rng);
    }
    return data;
}

static void BM_SequentialAdds(benchmark::State& state) {
    const std::size_t groups = static_cast<std::size_t>(state.range(0));

    state.PauseTiming();
    const auto operands = MakeOperands(groups);  // 全部放进 L1，避免内存淹没计算
    state.ResumeTiming();

    for (auto _ : state) {
        for (std::size_t g = 0; g < groups; ++g) {
            const float* base = &operands[g * kOperandsPerGroup];
            benchmark::DoNotOptimize(SequentialAdds(base));
        }
    }

    // 每组 5 次加法，依赖层级为 5
    state.counters["adds"] = benchmark::Counter(
        static_cast<double>(groups) * 5,
        benchmark::Counter::kIsIterationInvariantRate);

    state.counters["dep_levels"] = benchmark::Counter(
        static_cast<double>(groups) * 5,
        benchmark::Counter::kIsIterationInvariantRate);
}

static void BM_PairwiseAdds(benchmark::State& state) {
    const std::size_t groups = static_cast<std::size_t>(state.range(0));

    state.PauseTiming();
    const auto operands = MakeOperands(groups);
    state.ResumeTiming();

    for (auto _ : state) {
        for (std::size_t g = 0; g < groups; ++g) {
            const float* base = &operands[g * kOperandsPerGroup];
            benchmark::DoNotOptimize(PairwiseAdds(base));
        }
    }

    // 同样 5 次加法，但关键路径只有 3 层
    state.counters["adds"] = benchmark::Counter(
        static_cast<double>(groups) * 5,
        benchmark::Counter::kIsIterationInvariantRate);

    state.counters["dep_levels"] = benchmark::Counter(
        static_cast<double>(groups) * 3,
        benchmark::Counter::kIsIterationInvariantRate);
}

BENCHMARK(BM_SequentialAdds)->Arg(256)->Arg(4096);
BENCHMARK(BM_PairwiseAdds)->Arg(256)->Arg(4096);

BENCHMARK_MAIN();